home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Pascal Super Library
/
Pascal Super Library (CW International)(1997).bin
/
COMM
/
PPL4P10A
/
XYMODEM.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1995-02-20
|
14KB
|
470 lines
(**********************************************)
(* Copyright (C) 1995 by *)
(* MarshallSoft Computing, Inc. *)
(**********************************************)
{ $DEFINE DEBUG}
{$I DEFINES.PAS}
unit xymodem;
interface
uses xypacket,term_io,crt,dos,file_io,PCL4P;
function XmodemTx(
Port : Integer; (* COM port [COM1,COM2,...] *)
Var Filename : String; (* filename buffer *)
OneKflag : Boolean) (* 1K flag *)
: Boolean;
function XmodemRx(
Port : Integer; (* COM port [COM1,COM2,...] *)
Var Filename : String; (* filename buffer *)
NCGbyte : Byte) (* NAK, 'C', or 'G' *)
: Boolean;
function YmodemTx(
Port : Integer; (* COM port [COM1,COM2,...] *)
Var Filespec : String; (* file spec buffer *)
OneKflag : Boolean) (* 1K flag *)
: Boolean;
function YmodemRx(
Port : Integer; (* COM port [COM1,COM2,...] *)
Var Filename : String; (* filename buffer *)
NCGbyte : Byte) (* NAK, 'C', or 'G' *)
: Boolean;
implementation
Const NAK = $15;
CAN = $18;
ESC = $1B;
Var
Buffer : BufferType;
function TxyModem(
Port : Integer; (* COM port [COM1,COM2,...] *)
Var Filename : String; (* filename buffer *)
OneKflag : Boolean; (* use 1K blocks when possible *)
BatchFlag: Boolean) (* send filename in packet 0 *)
: Boolean;
Label 999;
Var
i, k : Integer;
Code : Integer;
Flag : Boolean;
c : Char;
Packet : Integer;
PacketType : Char;
PacketNbr : Byte;
BlockSize : Word;
ReadSize : Word;
FirstPacket: Word;
EOTflag : Boolean;
CheckSum : Word;
Number1K : Word; (* total # 1K ( 8 records ) packets *)
Number128 : Word; (* total # 128 byte ( 1 record ) packets *)
NCGbyte : Byte;
FileBytes : LongInt;
RemainingBytes : LongInt;
EmptyFlag : Boolean;
Message : String;
Temp1 : String;
Temp2 : String;
Result : Word;
CPS : Integer;
Tics : LongInt;
Secs : LongInt;
begin
(* begin *)
fioInit;
BlockSize := 128;
Number128 := 0;
Number1K := 0;
NCGbyte := NAK;
EmptyFlag := FALSE;
EOTflag := FALSE;
if BatchFlag then
begin
if (Length(Filename)=0) then EmptyFlag := TRUE;
end;
if not EmptyFlag then
begin (* not EmptyFlag *)
if not fioOpen(Filename) then
begin
Message := 'Cannot open ' + Filename;
WriteMsg(Message);
TxyModem := FALSE;
goto 999;
end;
(* pre-read 1st block *)
fioPreRead;
end; (* not EmptyFlag *)
WriteMsg('XYMODEM send: waiting for receiver ');
(* compute # blocks *)
if EmptyFlag then
begin (* empty file *)
Number128 := 0;
Number1K := 0
end
else
begin (* file not empty *)
FileBytes := fioSize;
RemainingBytes := FileBytes;
if OneKflag
then Number1K := FileBytes div 1024
else Number1K := 0;
Number128 := (FileBytes - 1024 * Number1K) div 128;
if (128*Number128+1024*Number1K) < FileBytes
then Number128 := Number128 + 1;
Str(Number1K,Temp1);
Str(Number128,Temp2);
Message := Temp1+' 1K & '+Temp2+' 128-byte packets';
WriteMsg(Message);
end;
(* clear comm port [there may be several NAKs queued up] *)
Code := SioRxFlush(Port);
(* get receivers start up NAK or 'C' *)
if not TxStartup(Port,NCGbyte) then
begin
TxyModem := FALSE;
goto 999;
end;
(* loop over all packets *)
if BatchFlag
then FirstPacket := 0
else FirstPacket := 1;
(* transmit each packet in turn *)
Tics := SioTimer;
for Packet := FirstPacket to Number1K+Number128 do
begin
{$IFDEF DEBUG}
WriteLn('Packet=',Packet);
{$ENDIF}
(* user aborts ? *)
if KeyPressed then if (Ord(ReadKey) = CAN) then
begin
TxCAN(Port);
WriteMsg('Canceled by USER');
TxyModem := FALSE;
goto 999
end;
(* issue message *)
str(Packet,Temp1);
Message := 'Packet ' + Temp1;
WriteMsg(Message);
(* load up Buffer *)
if Packet=0 then
begin (* packet = 0 *)
if EmptyFlag then Buffer[0] := 0
else
begin (* not empty *)
(* copy filename to buffer *)
BlockSize := 128;
k := 0;
WriteLn('Sending ',Filename);
for i:= 1 to Length(Filename) do
begin
Buffer[k] := ord(Filename[i]);
k := k + 1;
end;
Buffer[k] := 0;
(* copy file length to buffer *)
k := k + 1;
Str(FileBytes,Temp1);
for i := 1 to Length(Temp1) do
begin
Buffer[k] := ord(Temp1[i]);
k := k + 1;
end;
(* pad remainder of buffer *)
for i := k to 127 do Buffer[i] := 0;
end (* not empty *)
end (* Packet = 0 *)
else
begin (* Packet > 0 *)
(* DATA Packet: use 1K or 128-byte blocks ? *)
if BatchFlag and (Packet <= Number1K)
then BlockSize := 1024
else BlockSize := 128;
(* compute # bytes to read *)
if RemainingBytes < BlockSize then ReadSize := RemainingBytes
else ReadSize := BlockSize;
(* read next block from disk *)
if not fioRead(Buffer,ReadSize,Result) then
begin
WriteMsg('Disk I/O error');
TxyModem := FALSE;
goto 999
end;
RemainingBytes := RemainingBytes - Result;
if Result <> ReadSize then
begin
WriteMsg('Unexpected EOF on disk read');
TxyModem := FALSE;
goto 999;
end;
(* pad short buffer with ^Z *)
if ReadSize < BlockSize then
for i:= ReadSize to BlockSize do Buffer[i] := $1A;
end; (* Packet > 0 *)
(* send this packet *)
if not TxPacket(Port,Packet,BlockSize,Buffer,NCGbyte) then
begin
TxyModem := FALSE;
goto 999
end;
(* must 'restart' after non null packet 0 *)
if (not EmptyFlag) and (Packet=0) then Flag := TxStartup(Port,NCGbyte);
end; (* end -- for(Packet) *)
(* done if empty packet 0 *)
if EmptyFlag then
begin
WriteMsg('Batch transfer completed');
TxyModem := TRUE;
goto 999;
end
else
begin
(* compute CPS *)
Secs := (SioTimer - Tics) div 18;
If Secs > 0 then CPS := Integer(FileBytes div Secs)
else CPS := 0;
WriteLn(Filename,' sent @ CPS = ',CPS);
end;
(* all done. send EOT up to 10 times *)
fioClose;
if not TxEOT(Port) then
begin
SayError(Port,'EOT not acknowledged');
TxyModem := FALSE;
goto 999;
end;
WriteMsg('Transfer completed');
TxyModem := TRUE;
999: end; (* end -- TxyModem *)
function RxyModem(
Port : Integer; (* COM port [COM1,COM2,...] *)
Var Filename : String; (* filename buffer *)
NCGbyte : Byte; (* NAK, 'C', or 'G' *)
BatchFlag: Boolean) (* get filename from packet 0 *)
: Boolean;
Label 999;
Var
i, k : Integer;
Packet : Integer; (* packet index *)
Code : Integer; (* return code *)
Flag : Boolean;
EOTflag : Boolean;
Message : String;
Temp : String;
Result : Integer;
CPS : Integer;
Tics : LongInt;
Secs : LongInt;
FirstPacket: Word;
PacketNbr : Byte;
FileBytes : LongInt;
BytesRX : LongInt;
EmptyFlag : Boolean;
PacketSize : Word;
(* begin *)
begin
fioInit;
BytesRX := 0;
EmptyFlag := FALSE;
EOTflag := FALSE;
WriteMsg('XYMODEM Receive: Waiting for Sender ');
(* clear comm port *)
Code := SioRxFlush(Port);
(* Send NAKs or 'C's *)
if not RxStartup(Port,NCGbyte) then
begin
RxyModem := FALSE;
goto 999;
end;
(* open file unless BatchFlag is on *)
if BatchFlag then FirstPacket := 0
else
begin (* not BatchFlag *)
FirstPacket := 1;
(* open Filename for write *)
if not fioCreate(Filename) then
begin
Message := 'Cannot open ' + Filename;
WriteMsg(Message);
RxyModem := FALSE;
goto 999;
end;
end; (* not BatchFlag *)
Tics := SioTimer;
(* get each packet in turn *)
for Packet := FirstPacket to MaxInt do
begin
{$IFDEF DEBUG}
WriteLn('Packet=',Packet);
{$ENDIF}
(* user aborts ? *)
if KeyPressed then if (Ord(ReadKey) = CAN) then
begin
TxCAN(Port);
WriteMsg('Canceled by USER');
RxyModem := FALSE;
goto 999
end;
(* issue message *)
str(Packet,Temp);
Message := 'Packet ' + Temp;
WriteMsg(Message);
PacketNbr := Packet AND $00ff;
(* get next packet *)
if not RxPacket(Port,Packet,PacketSize,Buffer,NCGbyte,EOTflag) then
begin
RxyModem := FALSE;
goto 999;
end;
(* packet 0 ? *)
if Packet = 0 then
begin (* Packet = 0 *)
if Buffer[0] = 0 then
begin
WriteMsg('Batch transfer complete');
RxyModem := TRUE;
goto 999;
end;
(* get filename *)
i := 0;
k := 1;
repeat
Filename[k] := chr(Buffer[i]);
i := i + 1;
k := k + 1;
until Buffer[i] = 0;
FileName[0] := chr(i);
(* get file size *)
i := i + 1;
k := 1;
repeat
Temp[k] := chr(Buffer[i]);
i := i + 1;
k := k + 1;
until Buffer[i] = 0;
Temp[0] := chr(k - 1);
Val(Temp,FileBytes,Result);
WriteLn('Receiving ',Filename);
end; (* Packet = 0 *)
(* all done if EOT was received *)
if EOTflag then
begin
Secs := (SioTimer - Tics) div 18;
If Secs > 0 then CPS := Integer(BytesRX div Secs)
else CPS := 0;
WriteLn(Filename,' received @ CPS = ',CPS);
fioClose;
WriteMsg('Transfer completed');
RxyModem := TRUE;
goto 999
end;
(* process the packet *)
if Packet = 0 then
begin
(* open file using filename in packet 0 *)
if not fioCreate(Filename) then
begin
Message := 'Cannot open ' + Filename;
WriteMsg(Message);
RxyModem := FALSE;
goto 999;
end;
(* must 'restart' after packet 0 *)
Flag := RxStartup(Port,NCGbyte);
end
else (* Packet > 0 [DATA packet] *)
begin (* write Buffer *)
if not fioWrite(Buffer,PacketSize) then
begin
WriteMsg('Disk I/O error');
RxyModem := FALSE;
goto 999
end;
BytesRX := BytesRX + PacketSize
end (* end -- else *)
end; (* end -- for(Packet) *)
999:end; (* end - RxyModem *)
function XmodemTx(
Port : Integer; (* COM port [COM1,COM2,...] *)
Var Filename : String; (* filename buffer *)
OneKflag : Boolean) (* 1K flag *)
: Boolean;
begin
if FetchName(Filename) then
XmodemTx := TxyModem(Port,Filename,OneKflag,False)
else XmodemTx := False;
end;
function XmodemRx(
Port : Integer; (* COM port [COM1,COM2,...] *)
Var Filename : String; (* filename buffer *)
NCGbyte : Byte) (* NAK, 'C', or 'G' *)
: Boolean;
begin
if FetchName(Filename) then
XmodemRx := RxyModem(Port,Filename,NCGbyte,False)
else XmodemRx := False;
end;
function YmodemTx(
Port : Integer; (* COM port [COM1,COM2,...] *)
Var Filespec : String; (* file spec buffer *)
OneKflag : Boolean) (* 1K flag *)
: Boolean;
Var
FileNbr : Integer;
DirInfo : SearchRec;
Filename : String;
begin
FileNbr := 0;
if FetchName(Filespec) then
repeat
FileNbr := FileNbr + 1;
if FileNbr = 1 then FindFirst(Filespec,AnyFile,DirInfo)
else FindNext(DirInfo);
if DosError <> 0 then
begin
(* send empty filename *)
Filename := '';
YmodemTx := TxyModem(Port,Filename,OneKflag,True);
exit;
end;
Filename := DirInfo.Name;
YmodemTx := TxyModem(Port,Filename,OneKflag,True);
until False;
end;
function YmodemRx(
Port : Integer; (* COM port [COM1,COM2,...] *)
Var Filename : String; (* filename buffer *)
NCGbyte : Byte) (* NAK, 'C', or 'G' *)
: Boolean;
begin
YmodemRx := True;
repeat
WriteMsg('Ready for next file');
Filename := '';
if not RxyModem(Port,Filename,NCGbyte,True) then
begin
YmodemRx := False;
exit
end
until KeyPressed or (Length(Filename) = 0)
end;
end.